--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Commit c0b0ddffd735a0d007c1be9a5e8563ec42fdafc0
Parents : 98a5dd7
Author : Ivan <e46112d44649266d71fe2193e00a4710>
Signature : T66BB85Valid, signed by author
Date : 2026-07-20T12:57:26-05:00
feat: update dependencies to RNS 1.4.0 and LXMF 1.1.0
Changes
34 files changed, 362 insertions(+), 69 deletions(-)
Diff
diff --git a/.github/actions/setup-dev-environment/action.yml b/.github/actions/setup-dev-environment/action.yml
index d97fb175..e3ecfcfd 100644
--- a/.github/actions/setup-dev-environment/action.yml
+++ b/.github/actions/setup-dev-environment/action.yml
@@ -50,9 +50,9 @@ runs:
if command -v python >/dev/null 2>&1; then
py=python
fi
- if "$py" -m pip install --user 'rns>=1.3.9' 2>/dev/null; then
+ if "$py" -m pip install --user 'rns>=1.4.0' 2>/dev/null; then
:
- elif "$py" -m pip install --user --break-system-packages 'rns>=1.3.9' 2>/dev/null; then
+ elif "$py" -m pip install --user --break-system-packages 'rns>=1.4.0' 2>/dev/null; then
:
else
echo "WARNING: could not install rnid via pip (tree verify may be skipped)" >&2
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ada7a46d..24ff5abb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -20,6 +20,7 @@ All notable changes to this project will be documented in this file.
- LXMFy 1.6.5 vendor refresh, wasmtime, mutation test tasks
- Network visualiser WebGL + WASM renderer (vis-network fallback) and Settings renderer preference
- Interfaces: internal mode, recursive path requests, announces-from-internal, discovery location command, and Backbone fast-flapping options (RNS 1.3.7 to 1.3.9)
+- Dependencies: **RNS** 1.4.0 and **LXMF** 1.1.0, with local propagation node controls for sequential stamp validation, static-peer bypass, max inbound syncs, transfer size reporting, and inbound delivery cancel
### Changed
diff --git a/android/app/build.gradle b/android/app/build.gradle
index af4797d4..37678117 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -13,7 +13,7 @@ def pythonTempDir = new File(buildDir, "python-tmp")
def vendorWheelDir = new File(rootProject.projectDir, "vendor")
def lxstPatchedWheel = new File(rootProject.projectDir, "vendor/lxst-0.4.8-py3-none-any.whl")
def bleakPatchedWheel = new File(rootProject.projectDir, "vendor/bleak-3.0.2-py3-none-any.whl")
-def rnsPatchedWheel = new File(rootProject.projectDir, "vendor/rns-1.3.9-py3-none-any.whl")
+def rnsPatchedWheel = new File(rootProject.projectDir, "vendor/rns-1.4.0-py3-none-any.whl")
def allAndroidAbis = ["arm64-v8a", "x86_64", "armeabi-v7a"]
def selectedAndroidAbis = (
project.findProperty("meshchatxAbis")
@@ -341,7 +341,7 @@ chaquopy {
// shim, usb4a context bridge, and able BLE stack so USB/BT/BLE RNode can
// run. RNode over TCP needs neither native module and always works.
install rnsPatchedWheel.absolutePath
- install "lxmf>=1.0.1"
+ install "lxmf>=1.1.0"
install "numpy==1.26.2"
install "chaquopy-libcodec2==1.2.0"
install "pycodec2==4.1.1"
diff --git a/meshchatx.rsm b/meshchatx.rsm
index 33582c11..73e12456 100644
Binary files a/meshchatx.rsm and b/meshchatx.rsm differ
diff --git a/meshchatx/meshchat.py b/meshchatx/meshchat.py
index 0b324591..694ca413 100644
--- a/meshchatx/meshchat.py
+++ b/meshchatx/meshchat.py
@@ -3851,7 +3851,7 @@ class ReticulumMeshChat:
if isinstance(stats, dict)
else _numeric(getattr(router, "propagation_per_sync_limit", 0))
)
- return {
+ result = {
"is_running": is_running,
"identity_hash": ctx.identity.hash.hex(),
"destination_hash": destination_hash,
@@ -3890,7 +3890,21 @@ class ReticulumMeshChat:
else getattr(router, "propagation_stamp_cost", 0)
),
),
+ "inbound_delivery_count": 0,
+ "max_inbound_syncs": int(
+ getattr(router, "propagation_max_inbound_syncs", 0) or 0,
+ ),
+ "sequential_validation": bool(
+ getattr(router, "propagation_sequential_validation", True),
+ ),
+ "static_peers_bypass_sequential": not bool(
+ getattr(router, "propagation_static_peer_sequential", False),
+ ),
}
+ if hasattr(router, "inbound_count"):
+ with contextlib.suppress(Exception):
+ result["inbound_delivery_count"] = int(router.inbound_count() or 0)
+ return result
def _get_reticulum_section(self):
try:
@@ -12494,16 +12508,24 @@ class ReticulumMeshChat:
router = self.message_router
current_state = None
current_progress = 0.0
+ transfer_size = None
if router is not None:
try:
current_state = router.propagation_transfer_state
current_progress = router.propagation_transfer_progress
+ transfer_size = getattr(
+ router,
+ "propagation_transfer_size",
+ None,
+ )
# COMPLETE is terminal, so reset to idle so the UI does not keep
# looking "busy" after a finished auto/manual sync.
if current_state == router.PR_COMPLETE:
with contextlib.suppress(Exception):
router.propagation_transfer_state = router.PR_IDLE
router.propagation_transfer_progress = 0.0
+ if hasattr(router, "propagation_transfer_size"):
+ router.propagation_transfer_size = None
except Exception:
pass
sync_metrics = self._collect_propagation_sync_metrics()
@@ -12521,6 +12543,13 @@ class ReticulumMeshChat:
last_result = None
if current_state is None:
current_state = 0
+ transfer_size_bytes = None
+ if isinstance(transfer_size, (int, float)) and transfer_size > 0:
+ transfer_size_bytes = int(transfer_size)
+ inbound_delivery_count = 0
+ if router is not None and hasattr(router, "inbound_count"):
+ with contextlib.suppress(Exception):
+ inbound_delivery_count = int(router.inbound_count() or 0)
return web.json_response(
{
"propagation_node_status": {
@@ -12528,6 +12557,8 @@ class ReticulumMeshChat:
current_state,
),
"progress": progress_pct,
+ "transfer_size_bytes": transfer_size_bytes,
+ "inbound_delivery_count": inbound_delivery_count,
"messages_received": last_result,
"messages_stored": sync_metrics["messages_stored"],
"delivery_confirmations": sync_metrics[
@@ -12578,6 +12609,32 @@ class ReticulumMeshChat:
},
)
+ @routes.post("/api/v1/lxmf/propagation-node/cancel-inbound")
+ async def propagation_node_cancel_inbound(request):
+ router = self.message_router
+ if router is None or not hasattr(router, "cancel_all_inbound"):
+ return web.json_response(
+ {
+ "message": "Inbound delivery cancellation is unavailable.",
+ },
+ status=503,
+ )
+ try:
+ cancelled = int(router.cancel_all_inbound() or 0)
+ except Exception as exc:
+ return web.json_response(
+ {
+ "message": f"Failed to cancel inbound deliveries: {exc}",
+ },
+ status=500,
+ )
+ return web.json_response(
+ {
+ "message": f"Cancelled {cancelled} inbound deliveries",
+ "cancelled": cancelled,
+ },
+ )
+
@routes.post("/api/v1/lxmf/propagation-node/stop")
async def propagation_node_stop(request):
self.config.lxmf_local_propagation_node_enabled.set(False)
@@ -18655,6 +18712,34 @@ class ReticulumMeshChat:
if self.config.lxmf_local_propagation_node_enabled.get():
self.message_router.announce_propagation_node()
+ if "lxmf_propagation_sequential_validation" in data:
+ value = self._parse_bool(
+ data["lxmf_propagation_sequential_validation"],
+ )
+ self.config.lxmf_propagation_sequential_validation.set(value)
+ if self.message_router is not None:
+ self.message_router.propagation_sequential_validation = value
+
+ if "lxmf_propagation_static_peers_bypass_sequential" in data:
+ value = self._parse_bool(
+ data["lxmf_propagation_static_peers_bypass_sequential"],
+ )
+ self.config.lxmf_propagation_static_peers_bypass_sequential.set(value)
+ if self.message_router is not None:
+ self.message_router.propagation_static_peer_sequential = not value
+
+ if "lxmf_propagation_max_inbound_syncs" in data:
+ value = self._coerce_int(data["lxmf_propagation_max_inbound_syncs"])
+ if value is None:
+ value = self.config.lxmf_propagation_max_inbound_syncs.get()
+ if value < 1:
+ value = 1
+ elif value > 64:
+ value = 64
+ self.config.lxmf_propagation_max_inbound_syncs.set(value)
+ if self.message_router is not None:
+ self.message_router.propagation_max_inbound_syncs = value
+
# update auto sync interval
if "lxmf_preferred_propagation_node_auto_sync_interval_seconds" in data:
value = self._coerce_int(
@@ -20896,6 +20981,9 @@ class ReticulumMeshChat:
"lxmf_user_icon_background_colour": ctx.config.lxmf_user_icon_background_colour.get(),
"lxmf_inbound_stamp_cost": ctx.config.lxmf_inbound_stamp_cost.get(),
"lxmf_propagation_node_stamp_cost": ctx.config.lxmf_propagation_node_stamp_cost.get(),
+ "lxmf_propagation_sequential_validation": ctx.config.lxmf_propagation_sequential_validation.get(),
+ "lxmf_propagation_static_peers_bypass_sequential": ctx.config.lxmf_propagation_static_peers_bypass_sequential.get(),
+ "lxmf_propagation_max_inbound_syncs": ctx.config.lxmf_propagation_max_inbound_syncs.get(),
"lxmf_flood_protection_enabled": ctx.config.lxmf_flood_protection_enabled.get(),
"lxmf_flood_threshold_per_minute": ctx.config.lxmf_flood_threshold_per_minute.get(),
"lxmf_flood_max_stamp_cost": ctx.config.lxmf_flood_max_stamp_cost.get(),
diff --git a/meshchatx/src/backend/config_manager.py b/meshchatx/src/backend/config_manager.py
index 2dc96232..19e8119b 100644
--- a/meshchatx/src/backend/config_manager.py
+++ b/meshchatx/src/backend/config_manager.py
@@ -106,6 +106,21 @@ class ConfigManager:
"lxmf_propagation_node_stamp_cost",
16,
) # for propagation node messages
+ self.lxmf_propagation_sequential_validation = self.BoolConfig(
+ self,
+ "lxmf_propagation_sequential_validation",
+ True,
+ )
+ self.lxmf_propagation_static_peers_bypass_sequential = self.BoolConfig(
+ self,
+ "lxmf_propagation_static_peers_bypass_sequential",
+ True,
+ )
+ self.lxmf_propagation_max_inbound_syncs = self.IntConfig(
+ self,
+ "lxmf_propagation_max_inbound_syncs",
+ 3,
+ )
self.lxmf_inbound_stamp_cost_before_block = self.IntConfig(
self,
"lxmf_inbound_stamp_cost_before_block",
diff --git a/meshchatx/src/backend/data/THIRD_PARTY_NOTICES.txt b/meshchatx/src/backend/data/THIRD_PARTY_NOTICES.txt
index 6c7c621d..2b465b96 100644
--- a/meshchatx/src/backend/data/THIRD_PARTY_NOTICES.txt
+++ b/meshchatx/src/backend/data/THIRD_PARTY_NOTICES.txt
@@ -46,7 +46,7 @@ frozenlist 1.8.0
idna 3.18
License: BSD-3-Clause
Author: Kim Davies <kim+pypi@gumleaf.org>
-lxmf 1.0.1
+lxmf 1.1.0
License: Reticulum License
Author: Mark Qvist
lxmfy 1.6.5
@@ -88,7 +88,7 @@ pyserial 3.5
reticulum-meshchatx 4.8.0
License: 0BSD AND MIT
Author: Quad4
-rns 1.3.9
+rns 1.4.0
License: Reticulum License
Author: Mark Qvist
wasmtime 46.0.1
diff --git a/meshchatx/src/backend/data/licenses_backend.json b/meshchatx/src/backend/data/licenses_backend.json
index e79c86da..ef16fc96 100644
--- a/meshchatx/src/backend/data/licenses_backend.json
+++ b/meshchatx/src/backend/data/licenses_backend.json
@@ -8,7 +8,7 @@
{
"name": "aiohttp",
"version": "3.14.1",
- "author": "—",
+ "author": "\u2014",
"license": "Apache-2.0 AND MIT"
},
{
@@ -32,7 +32,7 @@
{
"name": "audioop-lts",
"version": "0.2.2",
- "author": "—",
+ "author": "\u2014",
"license": "PSF-2.0"
},
{
@@ -50,7 +50,7 @@
{
"name": "cbor2",
"version": "6.1.1",
- "author": "Alex Grönholm <alex.gronholm@nextday.fi>",
+ "author": "Alex Gr\u00f6nholm <alex.gronholm@nextday.fi>",
"license": "MIT"
},
{
@@ -85,7 +85,7 @@
},
{
"name": "lxmf",
- "version": "1.0.1",
+ "version": "1.1.0",
"author": "Mark Qvist",
"license": "Reticulum License"
},
@@ -169,7 +169,7 @@
},
{
"name": "rns",
- "version": "1.3.9",
+ "version": "1.4.0",
"author": "Mark Qvist",
"license": "Reticulum License"
},
diff --git a/meshchatx/src/backend/identity_context.py b/meshchatx/src/backend/identity_context.py
index c2b1a435..cfad244b 100644
--- a/meshchatx/src/backend/identity_context.py
+++ b/meshchatx/src/backend/identity_context.py
@@ -256,10 +256,22 @@ class IdentityContext:
# 4. Initialize LXMF Router
propagation_stamp_cost = self.config.lxmf_propagation_node_stamp_cost.get()
+ max_inbound_syncs = self.config.lxmf_propagation_max_inbound_syncs.get()
+ if not isinstance(max_inbound_syncs, int) or max_inbound_syncs < 1:
+ max_inbound_syncs = 3
+ sequential_validation = bool(
+ self.config.lxmf_propagation_sequential_validation.get(),
+ )
+ static_sequential = not bool(
+ self.config.lxmf_propagation_static_peers_bypass_sequential.get(),
+ )
self.message_router = create_lxmf_router(
identity=self.identity,
storagepath=self.lxmf_router_path,
propagation_cost=propagation_stamp_cost,
+ max_inbound_syncs=max_inbound_syncs,
+ sequential_validation=sequential_validation,
+ static_sequential=static_sequential,
)
self.message_router.PROCESSING_INTERVAL = 1
self.message_router.delivery_per_transfer_limit = (
diff --git a/meshchatx/src/backend/interface_editor.py b/meshchatx/src/backend/interface_editor.py
index 8ce5daca..ab91d2e9 100644
--- a/meshchatx/src/backend/interface_editor.py
+++ b/meshchatx/src/backend/interface_editor.py
@@ -340,7 +340,7 @@ class InterfaceEditor:
interface_details: dict,
data: dict,
) -> str | None:
- """Persist BackboneInterface fast-flapping options (RNS 1.3.9)."""
+ """Persist BackboneInterface fast-flapping options (RNS 1.4.0)."""
err = InterfaceEditor.apply_yes_no_option(
interface_details,
data,
diff --git a/meshchatx/src/backend/meshchat_utils.py b/meshchatx/src/backend/meshchat_utils.py
index 82f6dc0f..df37fdb2 100644
--- a/meshchatx/src/backend/meshchat_utils.py
+++ b/meshchatx/src/backend/meshchat_utils.py
@@ -11,7 +11,14 @@ import RNS.vendor.umsgpack as msgpack
from LXMF import LXMRouter
-def create_lxmf_router(identity, storagepath, propagation_cost=None):
+def create_lxmf_router(
+ identity,
+ storagepath,
+ propagation_cost=None,
+ max_inbound_syncs=None,
+ sequential_validation=None,
+ static_sequential=None,
+):
"""Construct an LXMF.LXMRouter without signal-handler crashes off the main thread.
signal.signal only works on the main thread; on workers it is temporarily
@@ -20,23 +27,27 @@ def create_lxmf_router(identity, storagepath, propagation_cost=None):
if propagation_cost is None:
propagation_cost = 0
+ kwargs = {
+ "identity": identity,
+ "storagepath": storagepath,
+ "propagation_cost": propagation_cost,
+ }
+ if max_inbound_syncs is not None:
+ kwargs["max_inbound_syncs"] = max_inbound_syncs
+ if sequential_validation is not None:
+ kwargs["sequential_validation"] = sequential_validation
+ if static_sequential is not None:
+ kwargs["static_sequential"] = static_sequential
+
if threading.current_thread() != threading.main_thread():
original_signal = signal.signal
try:
signal.signal = lambda s, h: None
- return LXMF.LXMRouter(
- identity=identity,
- storagepath=storagepath,
- propagation_cost=propagation_cost,
- )
+ return LXMF.LXMRouter(**kwargs)
finally:
signal.signal = original_signal
else:
- return LXMF.LXMRouter(
- identity=identity,
- storagepath=storagepath,
- propagation_cost=propagation_cost,
- )
+ return LXMF.LXMRouter(**kwargs)
def parse_bool_query_param(value: str | None) -> bool:
diff --git a/meshchatx/src/backend/rnsh_manager.py b/meshchatx/src/backend/rnsh_manager.py
index 2f809c4f..1bfdc645 100644
--- a/meshchatx/src/backend/rnsh_manager.py
+++ b/meshchatx/src/backend/rnsh_manager.py
@@ -293,7 +293,7 @@ class RNSHSession:
# same shared instance and rpc_key) as the MeshChatX app. Without this
# rnsh bootstraps its own default config, becomes a mismatched shared
# instance client and fails RPC auth with "digest sent was rejected".
- # RNS 1.3.9+: --rnsconfig is the Reticulum config dir. -c/--config is
+ # RNS 1.4.0+: --rnsconfig is the Reticulum config dir. -c/--config is
# the rnsh config directory (HOME/.rnsh via _build_env).
config_path = self.resolved_config_dir
if config_path:
diff --git a/meshchatx/src/frontend/components/settings/SettingsPage.vue b/meshchatx/src/frontend/components/settings/SettingsPage.vue
index 8e3a783a..60846dd1 100644
--- a/meshchatx/src/frontend/components/settings/SettingsPage.vue
+++ b/meshchatx/src/frontend/components/settings/SettingsPage.vue
@@ -3699,6 +3699,59 @@
{{ $t("app.propagation_stamp_description") }}
</div>
</div>
+ <label
+ v-if="config.lxmf_local_propagation_node_enabled"
+ class="setting-toggle"
+ >
+ <Toggle
+ id="propagation-sequential-validation"
+ v-model="config.lxmf_propagation_sequential_validation"
+ @update:model-value="onLxmfPropagationSequentialValidationChange"
+ />
+ <span class="setting-toggle__label">
+ <span class="setting-toggle__title">{{
+ $t("app.propagation_sequential_validation")
+ }}</span>
+ <span class="setting-toggle__description">{{
+ $t("app.propagation_sequential_validation_description")
+ }}</span>
+ </span>
+ </label>
+ <label
+ v-if="config.lxmf_local_propagation_node_enabled"
+ class="setting-toggle"
+ >
+ <Toggle
+ id="propagation-static-peers-bypass-sequential"
+ v-model="config.lxmf_propagation_static_peers_bypass_sequential"
+ @update:model-value="onLxmfPropagationStaticPeersBypassChange"
+ />
+ <span class="setting-toggle__label">
+ <span class="setting-toggle__title">{{
+ $t("app.propagation_static_peers_bypass_sequential")
+ }}</span>
+ <span class="setting-toggle__description">{{
+ $t("app.propagation_static_peers_bypass_sequential_description")
+ }}</span>
+ </span>
+ </label>
+ <div v-if="config.lxmf_local_propagation_node_enabled" class="space-y-2">
+ <div class="text-sm font-medium text-gray-900 dark:text-gray-100">
+ {{ $t("app.propagation_max_inbound_syncs") }}
+ </div>
+ <input
+ v-model.number="config.lxmf_propagation_max_inbound_syncs"
+ type="number"
+ min="1"
+ max="64"
+ placeholder="3"
+ class="input-field"
+ @input="onLxmfPropagationMaxInboundSyncsChange"
+ />
+ <div class="text-xs text-gray-600 dark:text-gray-400">
+ {{ $t("app.propagation_max_inbound_syncs_description") }}
+ </div>
+ </div>
</div>
</section>
@@ -3893,6 +3946,9 @@ export default {
lxmf_propagation_transfer_limit_in_bytes: 1000 * 256,
lxmf_propagation_sync_limit_in_bytes: 1000 * 10240,
lxmf_local_propagation_node_enabled: null,
+ lxmf_propagation_sequential_validation: true,
+ lxmf_propagation_static_peers_bypass_sequential: true,
+ lxmf_propagation_max_inbound_syncs: 3,
lxmf_preferred_propagation_node_destination_hash: null,
lxmf_preferred_propagation_node_auto_select: null,
archives_max_storage_gb: 1,
@@ -5351,6 +5407,30 @@ export default {
);
}, 1000);
},
+ async onLxmfPropagationSequentialValidationChange(value) {
+ await this.updateConfig({
+ lxmf_propagation_sequential_validation: value,
+ });
+ },
+ async onLxmfPropagationStaticPeersBypassChange(value) {
+ await this.updateConfig({
+ lxmf_propagation_static_peers_bypass_sequential: value,
+ });
+ },
+ async onLxmfPropagationMaxInboundSyncsChange() {
+ if (this.saveTimeouts.propagation_max_inbound_syncs) {
+ clearTimeout(this.saveTimeouts.propagation_max_inbound_syncs);
+ }
+ this.saveTimeouts.propagation_max_inbound_syncs = setTimeout(async () => {
+ let v = Number(this.config.lxmf_propagation_max_inbound_syncs);
+ if (!v || v < 1) v = 1;
+ else if (v > 64) v = 64;
+ this.config.lxmf_propagation_max_inbound_syncs = v;
+ await this.updateConfig({
+ lxmf_propagation_max_inbound_syncs: v,
+ });
+ }, 1000);
+ },
async onLxmfFloodProtectionEnabledChange(value) {
await this.updateConfig({
lxmf_flood_protection_enabled: value,
diff --git a/meshchatx/src/frontend/js/registries/coreSettingsSectionKeywords.js b/meshchatx/src/frontend/js/registries/coreSettingsSectionKeywords.js
index 8e4842e9..274b766e 100644
--- a/meshchatx/src/frontend/js/registries/coreSettingsSectionKeywords.js
+++ b/meshchatx/src/frontend/js/registries/coreSettingsSectionKeywords.js
@@ -358,6 +358,12 @@ export const CORE_SETTINGS_SECTION_KEYWORDS = {
"app.auto_sync_interval",
"app.propagation_stamp_cost",
"app.propagation_stamp_description",
+ "app.propagation_sequential_validation",
+ "app.propagation_sequential_validation_description",
+ "app.propagation_static_peers_bypass_sequential",
+ "app.propagation_static_peers_bypass_sequential_description",
+ "app.propagation_max_inbound_syncs",
+ "app.propagation_max_inbound_syncs_description",
],
location: [
"app.location",
diff --git a/meshchatx/src/frontend/locales/de.json b/meshchatx/src/frontend/locales/de.json
index 4e8dd4fb..b884993e 100644
--- a/meshchatx/src/frontend/locales/de.json
+++ b/meshchatx/src/frontend/locales/de.json
@@ -501,7 +501,13 @@
"remote_management_allowed": "Remote management allow-list",
"remote_management_allowed_description": "Identity hashes allowed to query this instance remotely with rnstatus/rnpath. One 32-character hex hash per line.",
"remote_management_allowed_placeholder": "9fb6d773498fb3feda407ed8ef2c3229",
- "remote_management_allowed_save": "Save allow-list"
+ "remote_management_allowed_save": "Save allow-list",
+ "propagation_sequential_validation": "Sequential PN Stamp Validation",
+ "propagation_sequential_validation_description": "Validate inbound propagation sync stamp batches one at a time. Other peers receive a throttle response while a batch is validating. Disable only on fast hosts.",
+ "propagation_static_peers_bypass_sequential": "Static Peers Bypass Sequential Validation",
+ "propagation_static_peers_bypass_sequential_description": "Allow configured static peers to sync immediately even when another stamp batch is already validating.",
+ "propagation_max_inbound_syncs": "Max Concurrent Inbound Syncs",
+ "propagation_max_inbound_syncs_description": "How many concurrent inbound propagation sync transfers to accept. Extra offers are throttled. Range: 1-64. Default: 3."
},
"common": {
"open": "Öffnen",
@@ -1386,7 +1392,7 @@
"location_cmd_placeholder": "/path/to/gps-script",
"location_cmd_hint": "Absoluter Pfad zu einem Programm, das latitude,longitude,height ausgibt. Reticulum startet es für Discovery-Announces (RNS location_cmd).",
"block_fast_flapping_label": "Schnell wechselnde Clients blockieren",
- "block_fast_flapping_hint": "Ignoriert Clients, die sich zu schnell verbinden und trennen (RNS 1.3.9 BackboneInterface-Standard).",
+ "block_fast_flapping_hint": "Ignoriert Clients, die sich zu schnell verbinden und trennen (RNS 1.4.0 BackboneInterface-Standard).",
"fast_flapping_block_time_label": "Sperrzeit (Minuten)",
"fast_flapping_threshold_label": "Schwelle (Sekunden)",
"fast_flapping_grace_label": "Kulanz-Flaps"
diff --git a/meshchatx/src/frontend/locales/en.json b/meshchatx/src/frontend/locales/en.json
index 2474d417..6b46abdb 100644
--- a/meshchatx/src/frontend/locales/en.json
+++ b/meshchatx/src/frontend/locales/en.json
@@ -275,6 +275,12 @@
"last_synced_never": "Last synced: never.",
"propagation_stamp_cost": "Propagation Node Stamp Cost",
"propagation_stamp_description": "Require proof-of-work stamps for messages sent through your node. Higher values require more work. Range: 13-254. Default: 16. **Note:** Changing this requires a restart.",
+ "propagation_sequential_validation": "Sequential PN Stamp Validation",
+ "propagation_sequential_validation_description": "Validate inbound propagation sync stamp batches one at a time. Other peers receive a throttle response while a batch is validating. Disable only on fast hosts.",
+ "propagation_static_peers_bypass_sequential": "Static Peers Bypass Sequential Validation",
+ "propagation_static_peers_bypass_sequential_description": "Allow configured static peers to sync immediately even when another stamp batch is already validating.",
+ "propagation_max_inbound_syncs": "Max Concurrent Inbound Syncs",
+ "propagation_max_inbound_syncs_description": "How many concurrent inbound propagation sync transfers to accept. Extra offers are throttled. Range: 1-64. Default: 3.",
"language": "Language",
"select_language": "Select your preferred language.",
"tagline": "All-in-one Reticulum client",
@@ -1261,7 +1267,7 @@
"location_cmd_placeholder": "/path/to/gps-script",
"location_cmd_hint": "Absolute path to an executable that prints latitude,longitude,height. Reticulum runs it for discovery announces (RNS location_cmd).",
"block_fast_flapping_label": "Block fast-flapping clients",
- "block_fast_flapping_hint": "Ignore clients that connect and disconnect too quickly (RNS 1.3.9 BackboneInterface defaults).",
+ "block_fast_flapping_hint": "Ignore clients that connect and disconnect too quickly (RNS 1.4.0 BackboneInterface defaults).",
"fast_flapping_block_time_label": "Block time (minutes)",
"fast_flapping_threshold_label": "Threshold (seconds)",
"fast_flapping_grace_label": "Grace flaps",
diff --git a/meshchatx/src/frontend/locales/es.json b/meshchatx/src/frontend/locales/es.json
index b470f7e2..a01eeb60 100644
--- a/meshchatx/src/frontend/locales/es.json
+++ b/meshchatx/src/frontend/locales/es.json
@@ -501,7 +501,13 @@
"remote_management_allowed": "Remote management allow-list",
"remote_management_allowed_description": "Identity hashes allowed to query this instance remotely with rnstatus/rnpath. One 32-character hex hash per line.",
"remote_management_allowed_placeholder": "9fb6d773498fb3feda407ed8ef2c3229",
- "remote_management_allowed_save": "Save allow-list"
+ "remote_management_allowed_save": "Save allow-list",
+ "propagation_sequential_validation": "Sequential PN Stamp Validation",
+ "propagation_sequential_validation_description": "Validate inbound propagation sync stamp batches one at a time. Other peers receive a throttle response while a batch is validating. Disable only on fast hosts.",
+ "propagation_static_peers_bypass_sequential": "Static Peers Bypass Sequential Validation",
+ "propagation_static_peers_bypass_sequential_description": "Allow configured static peers to sync immediately even when another stamp batch is already validating.",
+ "propagation_max_inbound_syncs": "Max Concurrent Inbound Syncs",
+ "propagation_max_inbound_syncs_description": "How many concurrent inbound propagation sync transfers to accept. Extra offers are throttled. Range: 1-64. Default: 3."
},
"common": {
"open": "Abierto",
@@ -1334,7 +1340,7 @@
"location_cmd_placeholder": "/path/to/gps-script",
"location_cmd_hint": "Ruta absoluta a un ejecutable que imprime latitude,longitude,height. Reticulum lo ejecuta para announces de discovery (RNS location_cmd).",
"block_fast_flapping_label": "Bloquear clientes de flapping rápido",
- "block_fast_flapping_hint": "Ignora clientes que se conectan y desconectan demasiado rápido (valores por defecto de BackboneInterface en RNS 1.3.9).",
+ "block_fast_flapping_hint": "Ignora clientes que se conectan y desconectan demasiado rápido (valores por defecto de BackboneInterface en RNS 1.4.0).",
"fast_flapping_block_time_label": "Tiempo de bloqueo (minutos)",
"fast_flapping_threshold_label": "Umbral (segundos)",
"fast_flapping_grace_label": "Flaps de gracia"
diff --git a/meshchatx/src/frontend/locales/fi.json b/meshchatx/src/frontend/locales/fi.json
index fdad15ef..8bd86d43 100644
--- a/meshchatx/src/frontend/locales/fi.json
+++ b/meshchatx/src/frontend/locales/fi.json
@@ -501,7 +501,13 @@
"remote_management_allowed": "Remote management allow-list",
"remote_management_allowed_description": "Identity hashes allowed to query this instance remotely with rnstatus/rnpath. One 32-character hex hash per line.",
"remote_management_allowed_placeholder": "9fb6d773498fb3feda407ed8ef2c3229",
- "remote_management_allowed_save": "Save allow-list"
+ "remote_management_allowed_save": "Save allow-list",
+ "propagation_sequential_validation": "Sequential PN Stamp Validation",
+ "propagation_sequential_validation_description": "Validate inbound propagation sync stamp batches one at a time. Other peers receive a throttle response while a batch is validating. Disable only on fast hosts.",
+ "propagation_static_peers_bypass_sequential": "Static Peers Bypass Sequential Validation",
+ "propagation_static_peers_bypass_sequential_description": "Allow configured static peers to sync immediately even when another stamp batch is already validating.",
+ "propagation_max_inbound_syncs": "Max Concurrent Inbound Syncs",
+ "propagation_max_inbound_syncs_description": "How many concurrent inbound propagation sync transfers to accept. Extra offers are throttled. Range: 1-64. Default: 3."
},
"common": {
"open": "Avaa",
@@ -1334,7 +1340,7 @@
"location_cmd_placeholder": "/path/to/gps-script",
"location_cmd_hint": "Absoluuttinen polku ohjelmaan, joka tulostaa latitude,longitude,height. Reticulum ajaa sen discovery-announceja varten (RNS location_cmd).",
"block_fast_flapping_label": "Estaa nopea flapping",
- "block_fast_flapping_hint": "Ohittaa asiakkaat, jotka yhdistavat ja katkaisevat liian nopeasti (RNS 1.3.9 BackboneInterface-oletukset).",
+ "block_fast_flapping_hint": "Ohittaa asiakkaat, jotka yhdistavat ja katkaisevat liian nopeasti (RNS 1.4.0 BackboneInterface-oletukset).",
"fast_flapping_block_time_label": "Estoaika (minuuttia)",
"fast_flapping_threshold_label": "Kynnys (sekuntia)",
"fast_flapping_grace_label": "Armo-flapit"
diff --git a/meshchatx/src/frontend/locales/fr.json b/meshchatx/src/frontend/locales/fr.json
index fa6e5454..d5ef9fbf 100644
--- a/meshchatx/src/frontend/locales/fr.json
+++ b/meshchatx/src/frontend/locales/fr.json
@@ -501,7 +501,13 @@
"remote_management_allowed": "Remote management allow-list",
"remote_management_allowed_description": "Identity hashes allowed to query this instance remotely with rnstatus/rnpath. One 32-character hex hash per line.",
"remote_management_allowed_placeholder": "9fb6d773498fb3feda407ed8ef2c3229",
- "remote_management_allowed_save": "Save allow-list"
+ "remote_management_allowed_save": "Save allow-list",
+ "propagation_sequential_validation": "Sequential PN Stamp Validation",
+ "propagation_sequential_validation_description": "Validate inbound propagation sync stamp batches one at a time. Other peers receive a throttle response while a batch is validating. Disable only on fast hosts.",
+ "propagation_static_peers_bypass_sequential": "Static Peers Bypass Sequential Validation",
+ "propagation_static_peers_bypass_sequential_description": "Allow configured static peers to sync immediately even when another stamp batch is already validating.",
+ "propagation_max_inbound_syncs": "Max Concurrent Inbound Syncs",
+ "propagation_max_inbound_syncs_description": "How many concurrent inbound propagation sync transfers to accept. Extra offers are throttled. Range: 1-64. Default: 3."
},
"common": {
"open": "Ouvrir",
@@ -1334,7 +1340,7 @@
"location_cmd_placeholder": "/path/to/gps-script",
"location_cmd_hint": "Chemin absolu vers un exécutable qui affiche latitude,longitude,height. Reticulum l'exécute pour les announces de discovery (RNS location_cmd).",
"block_fast_flapping_label": "Bloquer le flapping rapide",
- "block_fast_flapping_hint": "Ignore les clients qui se connectent et se déconnectent trop rapidement (défauts BackboneInterface RNS 1.3.9).",
+ "block_fast_flapping_hint": "Ignore les clients qui se connectent et se déconnectent trop rapidement (défauts BackboneInterface RNS 1.4.0).",
"fast_flapping_block_time_label": "Durée de blocage (minutes)",
"fast_flapping_threshold_label": "Seuil (secondes)",
"fast_flapping_grace_label": "Flaps de grace"
diff --git a/meshchatx/src/frontend/locales/it.json b/meshchatx/src/frontend/locales/it.json
index eb83ff3e..e1cfa005 100644
--- a/meshchatx/src/frontend/locales/it.json
+++ b/meshchatx/src/frontend/locales/it.json
@@ -501,7 +501,13 @@
"remote_management_allowed": "Remote management allow-list",
"remote_management_allowed_description": "Identity hashes allowed to query this instance remotely with rnstatus/rnpath. One 32-character hex hash per line.",
"remote_management_allowed_placeholder": "9fb6d773498fb3feda407ed8ef2c3229",
- "remote_management_allowed_save": "Save allow-list"
+ "remote_management_allowed_save": "Save allow-list",
+ "propagation_sequential_validation": "Sequential PN Stamp Validation",
+ "propagation_sequential_validation_description": "Validate inbound propagation sync stamp batches one at a time. Other peers receive a throttle response while a batch is validating. Disable only on fast hosts.",
+ "propagation_static_peers_bypass_sequential": "Static Peers Bypass Sequential Validation",
+ "propagation_static_peers_bypass_sequential_description": "Allow configured static peers to sync immediately even when another stamp batch is already validating.",
+ "propagation_max_inbound_syncs": "Max Concurrent Inbound Syncs",
+ "propagation_max_inbound_syncs_description": "How many concurrent inbound propagation sync transfers to accept. Extra offers are throttled. Range: 1-64. Default: 3."
},
"common": {
"open": "Apri",
@@ -1386,7 +1392,7 @@
"location_cmd_placeholder": "/path/to/gps-script",
"location_cmd_hint": "Percorso assoluto a un eseguibile che stampa latitude,longitude,height. Reticulum lo esegue per gli announce di discovery (RNS location_cmd).",
"block_fast_flapping_label": "Blocca client con flapping rapido",
- "block_fast_flapping_hint": "Ignora client che si connettono e disconnettono troppo in fretta (default BackboneInterface RNS 1.3.9).",
+ "block_fast_flapping_hint": "Ignora client che si connettono e disconnettono troppo in fretta (default BackboneInterface RNS 1.4.0).",
"fast_flapping_block_time_label": "Tempo di blocco (minuti)",
"fast_flapping_threshold_label": "Soglia (secondi)",
"fast_flapping_grace_label": "Flap di grazia"
diff --git a/meshchatx/src/frontend/locales/nl.json b/meshchatx/src/frontend/locales/nl.json
index 1ec3a8b7..b20653cf 100644
--- a/meshchatx/src/frontend/locales/nl.json
+++ b/meshchatx/src/frontend/locales/nl.json
@@ -501,7 +501,13 @@
"remote_management_allowed": "Remote management allow-list",
"remote_management_allowed_description": "Identity hashes allowed to query this instance remotely with rnstatus/rnpath. One 32-character hex hash per line.",
"remote_management_allowed_placeholder": "9fb6d773498fb3feda407ed8ef2c3229",
- "remote_management_allowed_save": "Save allow-list"
+ "remote_management_allowed_save": "Save allow-list",
+ "propagation_sequential_validation": "Sequential PN Stamp Validation",
+ "propagation_sequential_validation_description": "Validate inbound propagation sync stamp batches one at a time. Other peers receive a throttle response while a batch is validating. Disable only on fast hosts.",
+ "propagation_static_peers_bypass_sequential": "Static Peers Bypass Sequential Validation",
+ "propagation_static_peers_bypass_sequential_description": "Allow configured static peers to sync immediately even when another stamp batch is already validating.",
+ "propagation_max_inbound_syncs": "Max Concurrent Inbound Syncs",
+ "propagation_max_inbound_syncs_description": "How many concurrent inbound propagation sync transfers to accept. Extra offers are throttled. Range: 1-64. Default: 3."
},
"common": {
"open": "Openen",
@@ -1334,7 +1340,7 @@
"location_cmd_placeholder": "/path/to/gps-script",
"location_cmd_hint": "Absoluut pad naar een uitvoerbaar bestand dat latitude,longitude,height print. Reticulum voert dit uit voor discovery-announces (RNS location_cmd).",
"block_fast_flapping_label": "Snelle flapping-clients blokkeren",
- "block_fast_flapping_hint": "Negeert clients die te snel verbinden en verbreken (RNS 1.3.9 BackboneInterface-standaarden).",
+ "block_fast_flapping_hint": "Negeert clients die te snel verbinden en verbreken (RNS 1.4.0 BackboneInterface-standaarden).",
"fast_flapping_block_time_label": "Blokkeertijd (minuten)",
"fast_flapping_threshold_label": "Drempel (seconden)",
"fast_flapping_grace_label": "Grace-flaps"
diff --git a/meshchatx/src/frontend/locales/ru.json b/meshchatx/src/frontend/locales/ru.json
index f0ba44ca..98d4e039 100644
--- a/meshchatx/src/frontend/locales/ru.json
+++ b/meshchatx/src/frontend/locales/ru.json
@@ -501,7 +501,13 @@
"remote_management_allowed": "Remote management allow-list",
"remote_management_allowed_description": "Identity hashes allowed to query this instance remotely with rnstatus/rnpath. One 32-character hex hash per line.",
"remote_management_allowed_placeholder": "9fb6d773498fb3feda407ed8ef2c3229",
- "remote_management_allowed_save": "Save allow-list"
+ "remote_management_allowed_save": "Save allow-list",
+ "propagation_sequential_validation": "Sequential PN Stamp Validation",
+ "propagation_sequential_validation_description": "Validate inbound propagation sync stamp batches one at a time. Other peers receive a throttle response while a batch is validating. Disable only on fast hosts.",
+ "propagation_static_peers_bypass_sequential": "Static Peers Bypass Sequential Validation",
+ "propagation_static_peers_bypass_sequential_description": "Allow configured static peers to sync immediately even when another stamp batch is already validating.",
+ "propagation_max_inbound_syncs": "Max Concurrent Inbound Syncs",
+ "propagation_max_inbound_syncs_description": "How many concurrent inbound propagation sync transfers to accept. Extra offers are throttled. Range: 1-64. Default: 3."
},
"common": {
"open": "Открыть",
@@ -1386,7 +1392,7 @@
"location_cmd_placeholder": "/path/to/gps-script",
"location_cmd_hint": "Абсолютный путь к исполняемому файлу, печатающему latitude,longitude,height. Reticulum запускает его для discovery-announces (RNS location_cmd).",
"block_fast_flapping_label": "Блокировать быстрый flapping",
- "block_fast_flapping_hint": "Игнорирует клиентов, которые слишком быстро подключаются и отключаются (стандарты BackboneInterface RNS 1.3.9).",
+ "block_fast_flapping_hint": "Игнорирует клиентов, которые слишком быстро подключаются и отключаются (стандарты BackboneInterface RNS 1.4.0).",
"fast_flapping_block_time_label": "Время блокировки (минуты)",
"fast_flapping_threshold_label": "Порог (секунды)",
"fast_flapping_grace_label": "Льготные flaps"
diff --git a/meshchatx/src/frontend/locales/zh.json b/meshchatx/src/frontend/locales/zh.json
index a8e064f8..a9357b66 100644
--- a/meshchatx/src/frontend/locales/zh.json
+++ b/meshchatx/src/frontend/locales/zh.json
@@ -501,7 +501,13 @@
"remote_management_allowed": "Remote management allow-list",
"remote_management_allowed_description": "Identity hashes allowed to query this instance remotely with rnstatus/rnpath. One 32-character hex hash per line.",
"remote_management_allowed_placeholder": "9fb6d773498fb3feda407ed8ef2c3229",
- "remote_management_allowed_save": "Save allow-list"
+ "remote_management_allowed_save": "Save allow-list",
+ "propagation_sequential_validation": "Sequential PN Stamp Validation",
+ "propagation_sequential_validation_description": "Validate inbound propagation sync stamp batches one at a time. Other peers receive a throttle response while a batch is validating. Disable only on fast hosts.",
+ "propagation_static_peers_bypass_sequential": "Static Peers Bypass Sequential Validation",
+ "propagation_static_peers_bypass_sequential_description": "Allow configured static peers to sync immediately even when another stamp batch is already validating.",
+ "propagation_max_inbound_syncs": "Max Concurrent Inbound Syncs",
+ "propagation_max_inbound_syncs_description": "How many concurrent inbound propagation sync transfers to accept. Extra offers are throttled. Range: 1-64. Default: 3."
},
"common": {
"open": "打开",
@@ -1334,7 +1340,7 @@
"location_cmd_placeholder": "/path/to/gps-script",
"location_cmd_hint": "可执行文件的绝对路径,输出 latitude,longitude,height。Reticulum 会在发现通告时运行它(RNS location_cmd)。",
"block_fast_flapping_label": "阻止快速抖动客户端",
- "block_fast_flapping_hint": "忽略连接与断开过快的客户端(RNS 1.3.9 BackboneInterface 默认值)。",
+ "block_fast_flapping_hint": "忽略连接与断开过快的客户端(RNS 1.4.0 BackboneInterface 默认值)。",
"fast_flapping_block_time_label": "封锁时间(分钟)",
"fast_flapping_threshold_label": "阈值(秒)",
"fast_flapping_grace_label": "宽限抖动次数"
diff --git a/pyproject.toml b/pyproject.toml
index 7c5a16bf..440d3210 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -21,10 +21,10 @@ classifiers = [
]
dependencies = [
"aiohttp>=3.14.1",
- "lxmf>=1.0.1",
+ "lxmf>=1.1.0",
"psutil>=7.2.2",
"pyserial>=3.5",
- "rns>=1.3.9",
+ "rns>=1.4.0",
"websockets>=16.0",
"bcrypt>=5.0.0,<6.0.0",
"aiohttp-session>=2.12.1,<3.0.0",
diff --git a/requirements.txt b/requirements.txt
index 2d7fa923..15502c6a 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -542,9 +542,9 @@ idna==3.18 \
--hash=sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2 \
--hash=sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848
# via yarl
-lxmf==1.0.1 \
- --hash=sha256:96fbf9a02dcd311fd31129724c08faa5f42a0e4e1bab63bea7552fbc983f4fb8 \
- --hash=sha256:d12ead448296cbd09203462d8dc96a26eb71ef168b4197b133a970d483a607ea
+lxmf==1.1.0 \
+ --hash=sha256:187e5cba257163ba1cffa1b49a33dc8893cf3b982397ccd77461ceaa5cd54af1 \
+ --hash=sha256:3836550364e059aa94eb955f9a862d20287643518d7a0b2a167b3b58c1d07cbd
# via
# lxst
# reticulum-meshchatx
@@ -985,9 +985,9 @@ pyserial==3.5 \
# via
# reticulum-meshchatx
# rns
-rns==1.3.9 \
- --hash=sha256:ceeac4799dda72b48a34b1e36de538e64009cba5b7b28d086918c0120ca8bfa4 \
- --hash=sha256:fd3745c1aba4dcbf8833fa87a3157ec9900745a32d6d96ba330d623a98932a15
+rns==1.4.0 \
+ --hash=sha256:a88c6ae15c289867b2d8ee8f6ba4363f4dc728283f892b0790dba226f7dddcae \
+ --hash=sha256:fa9e76d0a78bf253eae66137e6bbdc65f470db3950a95b034ce32ca845ff0e44
# via
# lxmf
# lxst
diff --git a/scripts/build-android-wheels-local.sh b/scripts/build-android-wheels-local.sh
index 175efcf2..9aebc124 100755
--- a/scripts/build-android-wheels-local.sh
+++ b/scripts/build-android-wheels-local.sh
@@ -30,7 +30,7 @@ Options:
--numpy-version V NumPy version used during pycodec2 build (default: 1.26.2)
--lxst-version V LXST wheel version for metadata patch (default: 0.4.8)
--bleak-version V bleak pure-python wheel version to vendor (default: 3.0.2)
- --rns-version V rns wheel version to patch (default: 1.3.9)
+ --rns-version V rns wheel version to patch (default: 1.4.0)
--no-lxst-patch Skip LXST metadata patch
--no-rns-patch Skip RNS Android RNodeInterface patch
--only-recipes LIST Comma-separated recipe directory names under
@@ -60,7 +60,7 @@ LIBCODEC2_VERSION="1.2.0"
NUMPY_VERSION="1.26.2"
LXST_VERSION="0.4.8"
BLEAK_VERSION="3.0.2"
-RNS_VERSION="1.3.9"
+RNS_VERSION="1.4.0"
PATCH_LXST="1"
PATCH_RNS="1"
ONLY_RECIPES=""
diff --git a/tests/backend/test_smoke_extended.py b/tests/backend/test_smoke_extended.py
index 1a80c7cd..fc8fead7 100644
--- a/tests/backend/test_smoke_extended.py
+++ b/tests/backend/test_smoke_extended.py
@@ -227,5 +227,31 @@ def test_lxmf_router_creation_smoke():
identity = RNS.Identity()
with tempfile.TemporaryDirectory() as tmpdir:
with patch("LXMF.LXMRouter") as mock_router:
- create_lxmf_router(identity, tmpdir)
- mock_router.assert_called()
+ create_lxmf_router(
+ identity,
+ tmpdir,
+ propagation_cost=16,
+ max_inbound_syncs=2,
+ sequential_validation=True,
+ static_sequential=False,
+ )
+ mock_router.assert_called_once()
+ kwargs = mock_router.call_args.kwargs
+ assert kwargs["propagation_cost"] == 16
+ assert kwargs["max_inbound_syncs"] == 2
+ assert kwargs["sequential_validation"] is True
+ assert kwargs["static_sequential"] is False
+
+
+def test_lxmf_router_creation_accepts_new_defaults():
+ """LXMF 1.1.0 LXMRouter accepts sequential/inbound sync kwargs."""
+ import inspect
+
+ import LXMF
+
+ params = inspect.signature(LXMF.LXMRouter.__init__).parameters
+ assert "max_inbound_syncs" in params
+ assert "sequential_validation" in params
+ assert "static_sequential" in params
+ assert hasattr(LXMF.LXMRouter, "inbound_count")
+ assert hasattr(LXMF.LXMRouter, "cancel_all_inbound")
\ No newline at end of file
diff --git a/uv.lock b/uv.lock
index b8c1f97b..c40fb492 100644
--- a/uv.lock
+++ b/uv.lock
@@ -1081,14 +1081,14 @@ wheels = [
[[package]]
name = "lxmf"
-version = "1.0.1"
+version = "1.1.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "rns" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/33/2b/b1df90fce728db3a0659da44bfa8f1337670ccc6a937b7a988c119a4b05c/lxmf-1.0.1.tar.gz", hash = "sha256:d12ead448296cbd09203462d8dc96a26eb71ef168b4197b133a970d483a607ea", size = 71315, upload-time = "2026-06-01T12:26:07.874Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/8b/69/2ba34eee87c8fa91605d5e35ecb33a3a6e65f43085c7d3e369b724e05e03/lxmf-1.1.0.tar.gz", hash = "sha256:187e5cba257163ba1cffa1b49a33dc8893cf3b982397ccd77461ceaa5cd54af1", size = 74933, upload-time = "2026-07-20T16:58:07.498Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/86/ff/4374bc1ed3a6b5e3d4c9c9e40793b7ecf77998d3a41eae66501155aac8f3/lxmf-1.0.1-py3-none-any.whl", hash = "sha256:96fbf9a02dcd311fd31129724c08faa5f42a0e4e1bab63bea7552fbc983f4fb8", size = 64470, upload-time = "2026-06-01T12:26:06.044Z" },
+ { url = "https://files.pythonhosted.org/packages/07/b4/5ad93f8920ced6d233ba2ff9ec6677f71db7412434da508478d49bb40fe2/lxmf-1.1.0-py3-none-any.whl", hash = "sha256:3836550364e059aa94eb955f9a862d20287643518d7a0b2a167b3b58c1d07cbd", size = 67948, upload-time = "2026-07-20T16:58:05.97Z" },
]
[[package]]
@@ -1951,14 +1951,14 @@ requires-dist = [
{ name = "bleak", specifier = ">=3.0.2,<4.0" },
{ name = "cbor2", specifier = ">=6.1.1" },
{ name = "cryptography", specifier = ">=49.0.0,<50.0.0" },
- { name = "lxmf", specifier = ">=1.0.1" },
+ { name = "lxmf", specifier = ">=1.1.0" },
{ name = "lxst", specifier = ">=0.5.0" },
{ name = "miniaudio", specifier = ">=1.70,<2.0" },
{ name = "ply", specifier = ">=3.11,<4.0" },
{ name = "psutil", specifier = ">=7.2.2" },
{ name = "pycparser", specifier = ">=3.0" },
{ name = "pyserial", specifier = ">=3.5" },
- { name = "rns", specifier = ">=1.3.9" },
+ { name = "rns", specifier = ">=1.4.0" },
{ name = "wasmtime", specifier = ">=28.0.0" },
{ name = "websockets", specifier = ">=16.0" },
]
@@ -1993,15 +1993,15 @@ wheels = [
[[package]]
name = "rns"
-version = "1.3.9"
+version = "1.4.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cryptography" },
{ name = "pyserial" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/66/52/28a6db2911f32feeffd9800a88929762321be14700a67a3f5d289ad9ecc0/rns-1.3.9.tar.gz", hash = "sha256:fd3745c1aba4dcbf8833fa87a3157ec9900745a32d6d96ba330d623a98932a15", size = 519005, upload-time = "2026-07-19T00:33:44.851Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/3c/45/5aaed5107e0d3f434aada725224e1c54af96555959da312c01e12228c1de/rns-1.4.0.tar.gz", hash = "sha256:fa9e76d0a78bf253eae66137e6bbdc65f470db3950a95b034ce32ca845ff0e44", size = 519727, upload-time = "2026-07-20T17:13:03.624Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/ac/ef/b9b3bccc082a70ebdf862147c83f2dc09ecce9fceed034af610fbc50af66/rns-1.3.9-py3-none-any.whl", hash = "sha256:ceeac4799dda72b48a34b1e36de538e64009cba5b7b28d086918c0120ca8bfa4", size = 606018, upload-time = "2026-07-19T00:33:39.354Z" },
+ { url = "https://files.pythonhosted.org/packages/56/4e/1a50351fba424b891a61e5f0fed9f3f631d7a034ae5edcc531d79562467c/rns-1.4.0-py3-none-any.whl", hash = "sha256:a88c6ae15c289867b2d8ee8f6ba4363f4dc728283f892b0790dba226f7dddcae", size = 606736, upload-time = "2026-07-20T17:12:58.403Z" },
]
[[package]]
diff --git a/vendor/lxmfy/README.md b/vendor/lxmfy/README.md
index a4ea5cca..1dabcfb4 100644
--- a/vendor/lxmfy/README.md
+++ b/vendor/lxmfy/README.md
@@ -19,7 +19,7 @@ Easily create LXMF bots for the Reticulum Network with this extensible framework
## Installation
-**Requirements:** Python 3.11+, [RNS](https://pypi.org/project/rns/) 1.3.5+, [LXMF](https://pypi.org/project/lxmf/) 1.0.1+ (installed automatically with LXMFy).
+**Requirements:** Python 3.11+, [RNS](https://pypi.org/project/rns/) 1.4.0+, [LXMF](https://pypi.org/project/lxmf/) 1.1.0+ (installed automatically with LXMFy).
There are many ways to install LXMFy, you pick:
diff --git a/vendor/lxmfy/pyproject.toml b/vendor/lxmfy/pyproject.toml
index cd78ad91..4450ed7a 100644
--- a/vendor/lxmfy/pyproject.toml
+++ b/vendor/lxmfy/pyproject.toml
@@ -15,8 +15,8 @@ classifiers = [
"Operating System :: OS Independent",
]
dependencies = [
- "lxmf>=1.0.1",
- "rns>=1.3.5"
+ "lxmf>=1.1.0",
+ "rns>=1.4.0"
]
[project.urls]
diff --git a/vendor/rns_filesync/README.md b/vendor/rns_filesync/README.md
index 8e3715b6..892dd345 100644
--- a/vendor/rns_filesync/README.md
+++ b/vendor/rns_filesync/README.md
@@ -51,7 +51,7 @@ pip install -e ".[dev]"
# or: make install-user
```
-Requires rns>=1.3.9. Current package version: **1.0.0**.
+Requires rns>=1.4.0. Current package version: **1.0.0**.
```bash
rns-filesync -v
diff --git a/vendor/rns_filesync/README_RU.md b/vendor/rns_filesync/README_RU.md
index e9ea2834..48d2f8cd 100644
--- a/vendor/rns_filesync/README_RU.md
+++ b/vendor/rns_filesync/README_RU.md
@@ -2,7 +2,7 @@
English README is the source of truth: [README.md](README.md).
-Кратко: библиотека и CLI для синхронизации каталогов через Reticulum (`rns>=1.3.9`).
+Кратко: библиотека и CLI для синхронизации каталогов через Reticulum (`rns>=1.4.0`).
Конфиг и ACL как у rngit: `~/.rns_filesync/config`, правила `r:hash` / `w:all`, файлы `.allowed`.
```bash
diff --git a/vendor/rns_filesync/pyproject.toml b/vendor/rns_filesync/pyproject.toml
index 57be99c2..9eaf375f 100644
--- a/vendor/rns_filesync/pyproject.toml
+++ b/vendor/rns_filesync/pyproject.toml
@@ -10,7 +10,7 @@ readme = "README.md"
license = { text = "BSD-2-Clause" }
requires-python = ">=3.10"
dependencies = [
- "rns>=1.3.9",
+ "rns>=1.4.0",
]
[project.optional-dependencies]
diff --git a/vendor/rns_filesync/requirements.txt b/vendor/rns_filesync/requirements.txt
index 717fcd58..f50b3c94 100644
--- a/vendor/rns_filesync/requirements.txt
+++ b/vendor/rns_filesync/requirements.txt
@@ -1 +1 @@
-rns>=1.3.9
+rns>=1.4.0
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────